﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Globalization;
using System.Windows.Media.Animation;

namespace Gmantis.Controls
{
    [TemplatePart(Name = "ContentControl", Type = typeof(ContentPresenter)), TemplateVisualState(Name = "Watermarked", GroupName = "WatermarkStates"), TemplateVisualState(Name = "InvalidFocused", GroupName = "ValidationStatesStates"), StyleTypedProperty(Property = "ValidationDecoratorStyle", StyleTargetType = typeof(ValidationDecorator)), TemplateVisualState(Name = "Valid", GroupName = "ValidationStatesStates"), TemplateVisualState(Name = "InvalidUnfocused", GroupName = "ValidationStatesStates"), TemplateVisualState(Name = "Unwatermarked", GroupName = "WatermarkStates"), TemplatePart(Name = "EditControl", Type = typeof(TextBoxBase))]
    public class TextEditableContentControl : EditableContentControl
    {
        // Fields
        internal ContentPresenter _elementContentControl;
        internal TextBoxBase _elementEditControl;
        internal bool _isLoaded;
        internal KeyEventArgs _lastKey;
        private int _oldSelectionLength;
        private int _oldSelectionStart;
        private string _oldText;
        private string _textBeforeEditing;
        public static readonly DependencyProperty CaretBrushProperty = DependencyProperty.Register("CaretBrush", typeof(Brush), typeof(TextEditableContentControl), null);
        internal const string ContentControlElementName = "ContentControl";
        public static readonly DependencyProperty DisabledCuesVisibilityProperty = DependencyProperty.Register("DisabledCuesVisibility", typeof(Visibility), typeof(TextEditableContentControl), new PropertyMetadata(Visibility.Visible));
        internal const string EditControlElementName = "EditControl";
        public static readonly DependencyProperty FocusCuesVisibilityProperty = DependencyProperty.Register("FocusCuesVisibility", typeof(Visibility), typeof(TextEditableContentControl), new PropertyMetadata(Visibility.Visible));
        internal bool IsReadOnly;
        public static readonly DependencyProperty IsWatermarkedProperty = DependencyProperty.Register("IsWatermarked", typeof(bool), typeof(TextEditableContentControl), new PropertyMetadata(new PropertyChangedCallback(TextEditableContentControl.OnIsWatermarkedPropertyChanged)));
        public static readonly DependencyProperty SelectionBackgroundProperty = DependencyProperty.Register("SelectionBackground", typeof(Brush), typeof(TextEditableContentControl), null);
        public static readonly DependencyProperty SelectionForegroundProperty = DependencyProperty.Register("SelectionForeground", typeof(Brush), typeof(TextEditableContentControl), null);
        public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register("TextAlignment", typeof(TextAlignment), typeof(TextEditableContentControl), null);
        public static readonly DependencyProperty ValidationDecoratorStyleProperty = DependencyProperty.Register("ValidationDecoratorStyle", typeof(Style), typeof(TextEditableContentControl), null);
        public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(object), typeof(TextEditableContentControl), null);

        // Events
        public event EventHandler<System.Windows.Input.KeyEventArgs> TextBoxKeyDown;

        public event EventHandler<System.Windows.Input.KeyEventArgs> TextBoxKeyUp;

        public event EventHandler<TextEditedEventArgs> TextEdited;

        public event EventHandler<ValidateInputEventArgs> ValidateInput;

        // Methods
        public TextEditableContentControl()
        {
            RoutedEventHandler handler = null;
            this._oldText = string.Empty;
            base.DefaultStyleKey = typeof(TextEditableContentControl);
            if (handler == null)
            {
                handler = (param0, param1) => this.ChangeVisualStateWatermark(false);
            }
            base.Loaded += handler;
            this.SetCustomDefaultValues();
        }

        protected void ChangeVisualStateWatermark(bool useTransitions)
        {
            if (this.IsWatermarked)
            {
                VisualStateHelper.GoToState(this, "Watermarked", useTransitions);
            }
            if (!this.IsWatermarked)
            {
                VisualStateHelper.GoToState(this, "Unwatermarked", useTransitions);
            }
        }

        private string ConvertToString(object item)
        {
            if (base.ContentConverter != null)
            {
                return base.ContentConverter.ConvertToString(item);
            }
            if (item != null)
            {
                return item.ToString();
            }
            return string.Empty;
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        private void InitializeEditControlPart()
        {
            this._elementEditControl.GotFocus += new RoutedEventHandler(this.textBox_GotFocus);
            this._elementEditControl.KeyDown += new KeyEventHandler(this.textBox_KeyDown);
            this._elementEditControl.BindInputMethodProperties(this);
            this._elementEditControl.TextChanged += new TextChangedEventHandler(this.textBox_TextChanged);
            this._elementEditControl.KeyUp += new KeyEventHandler(this.textBox_KeyUp);
            this.UpdateIsReadOnly();
        }

        internal override void OnActualContentChanged(object oldContent, object newContent)
        {
            if (this._isLoaded)
            {
                if (this.OnIsValidInput(this.ConvertToString(newContent)) && (this._elementEditControl != null))
                {
                    this.UpdateText(newContent);
                }
                base.UpdateVisualState();
            }
            this.UpdateIsWatermarked();
        }

        private void OnAfterApplyTemplate()
        {
            base.EditControl = this._elementEditControl;
            base.ContentControl = this._elementContentControl;
            this.OnActualContentChanged(null, base.ActualContent);
            base.UpdateVisualState();
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementEditControl = this.GetTemplateChild<TextBoxBase>("EditControl", true, ref errors);
            if (this._elementEditControl != null)
            {
                this.InitializeEditControlPart();
            }
            this._elementContentControl = this.GetTemplateChild<ContentPresenter>("ContentControl", true, ref errors);
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to TextEditableContentControl.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.ChangeVisualStateWatermark(false);
                this.OnAfterApplyTemplate();
            }
        }

        protected override void OnEditCanceled()
        {
            this._elementEditControl.Text = this._textBeforeEditing;
            base.OnEditCanceled();
        }

        protected override void OnIsInEditModeChanged(bool oldValue)
        {
            if (this._isLoaded)
            {
                if (!base.IsInEditMode)
                {
                    if (base.ContentConverter != null)
                    {
                        base.ActualContent = base.ContentConverter.ConvertFromString(this._elementEditControl.Text);
                    }
                }
                else
                {
                    this.UpdateIsReadOnly();
                    this.UpdateText(base.ActualContent);
                }
                base.OnIsInEditModeChanged(oldValue);
            }
            this.UpdateIsWatermarked();
        }

        private bool OnIsValidInput(string input)
        {
            ValidateInputEventArgs e = new ValidateInputEventArgs
            {
                Input = input,
                IsValidInput = true
            };
            if (this.ValidateInput != null)
            {
                this.ValidateInput(this, e);
            }
            return e.IsValidInput;
        }

        private static void OnIsWatermarkedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as TextEditableContentControl).ChangeVisualStateWatermark(true);
        }

        internal void OnTextChanged()
        {
            this.textBox_TextChanged(null, null);
        }

        private void SetCustomDefaultValues()
        {
            base.EditStarted += new EventHandler(this.textBox_EditStarted);
            base.ContentConverter = new StringToObjectConverter(true);
            base.UpdateVisualState();
        }

        protected override bool ShouldEnterEditModeOnKeyDown(Key key)
        {
            KeyEventArgs e = new KeyEventArgs
            {
                Key = key
            };
            return (KeyboardUtil.GetKeyString(e) != null);
        }

        private void textBox_EditStarted(object sender, EventArgs e)
        {
            this._textBeforeEditing = this._elementEditControl.Text;
        }

        private void textBox_GotFocus(object sender, RoutedEventArgs e)
        {
            this._elementEditControl.Select(0, this._elementEditControl.Text.Length);
        }

        private void textBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (this.TextBoxKeyDown != null)
            {
                this.TextBoxKeyDown(this, e);
            }
            this._lastKey = new KeyEventArgs(e);
            this._lastKey.Args = null;
        }

        private void textBox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            bool flag = false;
            switch (e.Key)
            {
                case Key.Enter:
                case Key.Escape:
                    if ((!this.OnIsValidInput(this._elementEditControl.Text) || (e.Key == Key.Escape)) && !string.IsNullOrEmpty(this._elementEditControl.Text))
                    {
                        this.OnEditCanceled();
                    }
                    flag = true;
                    break;
            }
            if (this.TextBoxKeyUp != null)
            {
                this.TextBoxKeyUp(this, e);
            }
            if (flag)
            {
                if (!e.Handled)
                {
                    base.IsInEditMode = false;
                }
                e.Handled = true;
            }
        }

        private void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (((this._lastKey != null) && (((KeyboardUtil.GetKeyString(this._lastKey) != null) || (this._lastKey.Key == Key.Back)) || ((this._lastKey.Key == Key.Delete) || ((this._lastKey.Key == Key.Z) && ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control))))) && (this.TextEdited != null))
            {
                TextEditedEventArgs args = new TextEditedEventArgs
                {
                    LastKey = this._lastKey.Key,
                    CurrentText = this._elementEditControl.Text,
                    CurrentSelectionStart = this._elementEditControl.SelectionStart,
                    NewText = this._elementEditControl.Text,
                    NewSelectionStart = this._elementEditControl.SelectionStart
                };
                this.TextEdited(this, args);
                this._elementEditControl.TextChanged -= new TextChangedEventHandler(this.textBox_TextChanged);
                if (!args.Cancel)
                {
                    int newSelectionStart;
                    int num2;
                    this._elementEditControl.Text = args.NewText;
                    if (this._elementEditControl.Text.Length > args.NewSelectionStart)
                    {
                        newSelectionStart = args.NewSelectionStart;
                        num2 = this._elementEditControl.Text.Length - newSelectionStart;
                    }
                    else
                    {
                        newSelectionStart = this._elementEditControl.Text.Length;
                        num2 = 0;
                    }
                    this._elementEditControl.Select(newSelectionStart, num2);
                }
                else
                {
                    this._elementEditControl.Text = this._oldText;
                    this._elementEditControl.Select(this._oldSelectionStart, this._oldSelectionLength);
                }
                this._elementEditControl.TextChanged += new TextChangedEventHandler(this.textBox_TextChanged);
            }
            this._oldText = this._elementEditControl.Text;
            this._oldSelectionStart = this._elementEditControl.SelectionStart;
            this._oldSelectionLength = this._elementEditControl.SelectionLength;
        }

        internal void UpdateIsReadOnly()
        {
            if (this._elementEditControl != null)
            {
                bool isReadOnly;
                if (!base.IsEnabled)
                {
                    isReadOnly = true;
                }
                else
                {
                    isReadOnly = this.IsReadOnly;
                }
                this._elementEditControl.IsReadOnly = isReadOnly;
            }
        }

        internal void UpdateIsWatermarked()
        {
            this.IsWatermarked = (!base.IsInEditMode && !base.IsDropDownOpen) && (base.ActualContent == null);
        }

        private void UpdateText(object content)
        {
            if (this._elementEditControl != null)
            {
                string str = this.ConvertToString(content) ?? "";
                this._oldText = str;
                this._elementEditControl.Text = str;
                try
                {
                    this._elementEditControl.Select(0, this._elementEditControl.Text.Length);
                }
                catch (NullReferenceException)
                {
                }
            }
        }

        // Properties
        public Brush CaretBrush
        {
            get { return (Brush)GetValue(CaretBrushProperty); }
            set { SetValue(CaretBrushProperty, value); }
        }

        public Visibility DisabledCuesVisibility
        {
            get { return (Visibility)GetValue(DisabledCuesVisibilityProperty); }
            set { SetValue(DisabledCuesVisibilityProperty, value); }
        }

        public TextBoxBase EditTextBox
        {
            get { return this._elementEditControl; }
        }

        public Visibility FocusCuesVisibility
        {
            get { return (Visibility)GetValue(FocusCuesVisibilityProperty); }
            set { SetValue(FocusCuesVisibilityProperty, value); }
        }

        public override bool IsDirty
        {
            get
            {
                return (this._elementEditControl.Text != this._textBeforeEditing);
            }
            set
            {
                if (!value && (this._elementEditControl != null))
                {
                    this._textBeforeEditing = this._elementEditControl.Text;
                }
            }
        }

        public bool IsWatermarked
        {
            get { return (bool)GetValue(IsWatermarkedProperty); }
            set { SetValue(IsWatermarkedProperty, value); }
        }

        public Brush SelectionBackground
        {
            get { return (Brush)GetValue(SelectionBackgroundProperty); }
            set { SetValue(SelectionBackgroundProperty, value); }
        }

        public Brush SelectionForeground
        {
            get { return (Brush)GetValue(SelectionForegroundProperty); }
            set { SetValue(SelectionForegroundProperty, value); }
        }

        public TextAlignment TextAlignment
        {
            get { return (TextAlignment)GetValue(TextAlignmentProperty); }
            set { SetValue(TextAlignmentProperty, value); }
        }

        public Style ValidationDecoratorStyle
        {
            get { return (Style)GetValue(ValidationDecoratorStyleProperty); }
            set { SetValue(ValidationDecoratorStyleProperty, value); }
        }

        public object Watermark
        {
            get { return GetValue(WatermarkProperty); }
            set { SetValue(WatermarkProperty, value); }
        }
    }
}
